#include "ListaRefinada.h"
#include "lista.h"




ListaRefinada::ListaRefinada(int n){


	//creo el arreglo

	infoVertices = new InfoVertex[n];


	//creo la particion
	//Particion* pptr;
	//pptr = new Particion();

	Double_linked<Particion>::Node* npptr;

	npptr = new Double_linked<Particion>::Node(Particion(),NULL,NULL);

	lr.pegarAtras(npptr);



    for(int i = 0; i < n; i++){
		//pongo los nodos en la lista de la primer particion

		(npptr->data).vertices.push_back(i);

		//guardo los punteros en el arreglo
		infoVertices[i].miNodo = ((npptr->data).vertices).tail;
		infoVertices[i].miParticion = npptr;
	}



}


ListaRefinada::~ListaRefinada()
{
  delete[] infoVertices;
}

void ListaRefinada::refinarDerecha(vector<int> s){

  /*  cout<<"COMENZANDO REFINAR DERECHA"<<endl<<endl;
    cout << "lista a refinar:" <<endl;
    display();
    cout << "estado nodos:" <<endl;
    displayInfoV(4);
    cout << "subconjunto:" <<endl;
    for(int i=0; i < s.size(); i++){
        cout << s[i] << " " ;
    }
    cout<<endl<<endl;
*/


    Double_linked<Particion*> fragmentadas;

	int vecino_actual = 0;
	Double_linked<Particion>::Node* partptr;
	Double_linked<int>::Node* idptr;
	Double_linked<Particion>::Node* npptr;
	//Particion* pptr;


	for(unsigned int i=0; i < s.size(); i++){

		//guardo la informacion del nodo
		vecino_actual = s[i];
		partptr = infoVertices[vecino_actual].miParticion;
		idptr = infoVertices[vecino_actual].miNodo;


		//veo si es un nodo visitado
		if(!(infoVertices[vecino_actual].visitado)){


            //si la particion tiene solo a s[i], no hago nada
			  //  if(!((partptr->data).vertices.unitaria())){

                        //veo si la particion ya fue cortada
                        if(!((partptr->data).fragmentada)){

                            /*creo una nueva particion a la derecha de donde estaba la original,
                            con s[i]	*/

                            //saco el nodo que voy a mover
                                (partptr->data).vertices.erase(idptr);

                            //creo la nueva particion


                                npptr = new Double_linked<Particion>::Node(Particion(),NULL,NULL);
                                (npptr->data).vertices.pegarAtras(idptr);

                            //actualizo la info de particion del vertice
                                infoVertices[vecino_actual].miParticion = npptr;


                            // coloco la nueva a la derecha de la vieja.

                            lr.pegarADerechaDe(partptr,npptr);


                        // marco la vieja como partida

                            (partptr->data).fragmentada = true;

                        // la agrego a la lista de fragmentadas

                            fragmentadas.push_back(&(partptr->data));

                        // seteo el puntero de la estructura particion, que apunta al puntero
                        //de fragmentadas, esto sirve por si se borra la particion.
                             (partptr->data).fragAux =  &((fragmentadas.tail)->data);

                }else{
					//identifico a la siguiente particion
					npptr = partptr->next;

					//saco el nodo que voy a mover
					(partptr->data).vertices.erase(idptr);


					//actualizo la info de particion del vertice
					infoVertices[vecino_actual].miParticion = npptr;


					//lo coloco en npptr
					 (npptr->data).vertices.pegarAtras(idptr);


                }

                //si queda una particion vacia la borro
                if((partptr->data).vertices.empty()){
                       lr.erase(partptr);
                       //seteo en null el puntero en fragmentadas a traves de fragAux
                       if(((partptr->data).fragAux)!=NULL){*((partptr->data).fragAux) = NULL;}
                       //borro la particion
                       delete partptr;

                }

		}
	}



	//desmarco las particiones fragmentadas

	Double_linked<Particion*>::Node* iterFrag;

	iterFrag = fragmentadas.head;

	while(iterFrag!=NULL){
	    if((iterFrag->data)!=NULL){
		(iterFrag->data)->fragmentada = false;}
		iterFrag = iterFrag->next;
	}


}

void ListaRefinada::refinarIzquierda(vector<int> s){

  /*  cout<<"COMENZANDO REFINAR DERECHA"<<endl<<endl;
    cout << "lista a refinar:" <<endl;
    display();
    cout << "estado nodos:" <<endl;
    displayInfoV(4);
    cout << "subconjunto:" <<endl;
    for(int i=0; i < s.size(); i++){
        cout << s[i] << " " ;
    }
    cout<<endl<<endl;
*/


    Double_linked<Particion*> fragmentadas;

	int vecino_actual = 0;
	Double_linked<Particion>::Node* partptr;
	Double_linked<int>::Node* idptr;
	Double_linked<Particion>::Node* npptr;
	//Particion* pptr;


	for(unsigned int i=0; i < s.size(); i++){

		//guardo la informacion del nodo
		vecino_actual = s[i];
		partptr = infoVertices[vecino_actual].miParticion;
		idptr = infoVertices[vecino_actual].miNodo;


		//veo si es un nodo visitado
		if(!(infoVertices[vecino_actual].visitado)){


            //si la particion tiene solo a s[i], no hago nada
			  //  if(!((partptr->data).vertices.unitaria())){

                        //veo si la particion ya fue cortada
                        if(!((partptr->data).fragmentada)){

                            /*creo una nueva particion a la derecha de donde estaba la original,
                            con s[i]	*/

                            //saco el nodo que voy a mover
                                (partptr->data).vertices.erase(idptr);

                            //creo la nueva particion


                                npptr = new Double_linked<Particion>::Node(Particion(),NULL,NULL);
                                (npptr->data).vertices.pegarAtras(idptr);

                            //actualizo la info de particion del vertice
                                infoVertices[vecino_actual].miParticion = npptr;


                            // coloco la nueva a la derecha de la vieja.

                            lr.pegarAIzquierdaDe(partptr,npptr);


                        // marco la vieja como partida

                            (partptr->data).fragmentada = true;


                        // la agrego a la lista de fragmentadas

                            fragmentadas.push_back(&(partptr->data));

                        // seteo el puntero de la estructura particion, que apunta al puntero
                        //de fragmentadas, esto sirve por si se borra la particion.
                             (partptr->data).fragAux =  &((fragmentadas.tail)->data);

                }else{
					//identifico a la particion anterior
					npptr = partptr->prev;

					//saco el nodo que voy a mover
					(partptr->data).vertices.erase(idptr);


					//actualizo la info de particion del vertice
					infoVertices[vecino_actual].miParticion = npptr;


					//lo coloco en npptr
					 (npptr->data).vertices.pegarAtras(idptr);


                }

                //si queda una particion vacia la borro
                if((partptr->data).vertices.empty()){
                       lr.erase(partptr);
                       //seteo en null el puntero en fragmentadas a traves de fragAux
                       if(((partptr->data).fragAux)!=NULL){*((partptr->data).fragAux) = NULL;}
                       delete partptr;

                }

		}
	}



	//desmarco las particiones fragmentadas
	Double_linked<Particion*>::Node* iterFrag;

	iterFrag = fragmentadas.head;

	while(iterFrag!=NULL){
	    if((iterFrag->data)!=NULL){
		(iterFrag->data)->fragmentada = false;}
		iterFrag = iterFrag->next;
	}


}



void ListaRefinada::display(){
	Double_linked<Particion>::Node* partptr = lr.head;
	Double_linked<int>::Node* idptr;
	int i = 0;

	while(partptr!=NULL){

		cout << "P" << i << ": " ;

		idptr = (partptr->data).vertices.head;

		while (idptr!=NULL){
			cout << (idptr->data) << " " ;
			idptr = (idptr->next);
		}
		partptr = partptr->next;
		i++;
	}
}


void ListaRefinada::displayInfoV(int n){

	/*Double_linked<Particion>::Node* partptr ;
	Double_linked<int>::Node* idptr;*/

	for(int i=0; i < n; i++){
	cout << "NODO " << i <<endl;
	cout << "   particion " << infoVertices[i].miParticion<<endl;
	cout <<	"   vertice " <<  infoVertices[i].miNodo<<endl ;
	cout<< "    next " << infoVertices[i].miParticion->next<<endl;
    cout<< "    prev " << infoVertices[i].miParticion->prev<<endl;
    cout <<endl;


	}


}































